package com.test;

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.List;
import java.util.concurrent.ExecutionException;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
import javax.swing.text.DefaultCaret;

import org.apache.log4j.Logger;

public class DiskSpaceUsed {
	
	static Logger logger = Logger.getLogger(DiskSpaceUsed.class);

	enum Operation {
		Connect, ComputeDirStats
	}

	private JFrame frame;
	private JTextArea log = new JTextArea();
	private static final String newline = "\n";
	private JScrollPane scrollPane = new JScrollPane();
	private JButton scan = new JButton("Scan");
	private final JButton relayout = new JButton("Relayout");



	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					DiskSpaceUsed window = new DiskSpaceUsed();
					window.frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public DiskSpaceUsed() {
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frame = new JFrame();
		frame.setBounds(100, 100, 450, 300);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		scan.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				JFileChooser chooser=new JFileChooser();
				chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
				int returnVal=chooser.showOpenDialog(frame);
		        if (returnVal == JFileChooser.APPROVE_OPTION) {
		            File file = chooser.getSelectedFile();
		            //This is where a real application would open the file.
		            log.setText("Opening: " + file.getName() + "." + newline);
		            scan.setEnabled(false);
//		            frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		            LoadDirectories loaddir=new LoadDirectories(file, log);
		            loaddir.execute();
		            // This code is now done in the SwingWorker thread
//		            DSUPanel root=createTree(file, log);
//		            scrollPane.setViewportView(root.getPanel());
		        } else {
		            log.append("Open command cancelled by user." + newline);
		        }
				
			}
		});
		frame.getContentPane().add(scan, BorderLayout.NORTH);
		
		frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
		
		JScrollPane scrollPane_1 = new JScrollPane();
		frame.getContentPane().add(scrollPane_1, BorderLayout.SOUTH);
		DefaultCaret caret=(DefaultCaret) log.getCaret();
		caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
		log.setRows(5);
		
		scrollPane_1.setViewportView(log);
		relayout.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					GLManager.traverseComponents((JComponent)scrollPane.getViewport().getView(), false);
				} catch (Exception e1) {
					e1.printStackTrace();
				}
			}
		});
		frame.getContentPane().add(relayout, BorderLayout.WEST);
	}
//	private void createTree(DSUPanel root) {
//		File file=root.getFile();
//		if (file.isDirectory()) {
//			File[] files=file.listFiles();
//			for (File dirfile : files) {
//				DSUPanel child=root.addChild(dirfile);
//				if (dirfile.isDirectory()) createTree(child);
//			}
//		}
//		return;
//	}
	private class DSUPanelData {
		
		public DSUPanel getPanel() {
			return panel;
		}
		public DSUPanel getParent() {
			return parent;
		}
		public Operation getOperation() {
			return operation;
		}
		public boolean isLastChild() {
			return lastChild;
		}
		private DSUPanel panel;
		private DSUPanel parent;
		private Operation operation;
		private boolean lastChild;
		
		public DSUPanelData(DSUPanel panel, DSUPanel parent, boolean lastChild, Operation operation) {
			this(panel, parent, operation);
			this.lastChild=lastChild;
		}
		public DSUPanelData(DSUPanel panel, DSUPanel parent, Operation operation) {
			this.operation=operation;
			this.panel=panel;
			this.parent=parent;
		}
	}
	
	private class LoadDirectories extends SwingWorker<DSUPanelBoxLayout, DSUPanelData> {

		private File file;
		private JTextArea log;
		private DSUPanel root;

		public LoadDirectories(File file, JTextArea log) {
			this.file=file;
			this.log=log;
		}
		@Override
		protected void process(List<DSUPanelData> chunks) {
			logger.debug("Entered process loop with "+chunks.size()+" events\n");
			for (DSUPanelData dsuPanelData : chunks) {
				DSUPanel panel=dsuPanelData.getPanel();
				DSUPanel parent=dsuPanelData.getParent();
				Operation operation=dsuPanelData.getOperation();
				boolean isLastChild=dsuPanelData.isLastChild();
				if (parent!=null) {
					if (operation==Operation.ComputeDirStats) parent.computeDirStats(panel, isLastChild);
					else if (operation==Operation.Connect) parent.connectChild(panel);
				} else { // root element, connect to UI immediately
					scrollPane.setViewportView(panel.getPanel());
				}
			}
			if (root!=null) {
				// update the viewport
				scrollPane.setViewportView(root.getPanel());
			}
			frame.repaint();
		}

		@Override
		protected void done() {
			try {
				scrollPane.setViewportView(get().getPanel());
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			} finally {
				frame.setCursor(Cursor.getDefaultCursor());
	            scan.setEnabled(true);
			}
		}

		@Override
		protected DSUPanelBoxLayout doInBackground() throws Exception {
			return createTree(file, log, null, 1);
		}

		private DSUPanelBoxLayout createTree(File file, JTextArea log, DSUPanel parent, int level) {
			DSUPanelBoxLayout node=new DSUPanelBoxLayout(file, log, level, true);
			log.append("Scanning directory "+file.getName()+"\n");
			Thread.yield();
			if (file.equals(this.file)) { // root element
				// publish immediately so we can attach to UI
				root=node; // keep it there for future updates
				publish(new DSUPanelData(node, null, false, Operation.ComputeDirStats)); // null indicates root
			} else {
				publish(new DSUPanelData(node, parent, Operation.Connect)); // connect this folder
			}
			Thread.yield();
			if (file.isDirectory()) {
				File[] files=file.listFiles();
				if (files!=null) {
					for (int i = 0; i < files.length; i++) {
						File dirfile = files[i];
						Thread.yield();
						DSUPanel child;
						if (dirfile.isDirectory()) child=createTree(dirfile, log, node, level+1);
						else {
							child=new DSUPanelBoxLayout(dirfile, log, level+1, false);
							publish(new DSUPanelData(child, node, Operation.Connect)); // connect this file
						}
						publish(new DSUPanelData(child, node, (i+1)==files.length, Operation.ComputeDirStats));
						Thread.yield();
					}				
				}
			}
			return node;
		}
		
	}
	

}
